package com.zmn.oms.third.shunfeng.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zmn.base.common.data.common.dro.area.AreaDRO;
import com.zmn.base.common.data.dubbo.interfaces.area.AreaListRemoteService;
import com.zmn.base.product.common.dto.product.ec.ProductBaseDRO;
import com.zmn.base.product.dubbo.interfaces.channel.product.third.ChannelProductThirdListRemoteService;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.consts.GlobalDict;
import com.zmn.manager.redis.RedisManager;
import com.zmn.oms.business.interfaces.baidumap.BaiduMapBService;
import com.zmn.oms.business.interfaces.track.OrderTrackBService;
import com.zmn.oms.common.constant.*;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.model.bo.order.OrderBO;
import com.zmn.oms.model.dto.baidumap.LngLatLocation;
import com.zmn.oms.model.dto.order.proxy.CancelOrderDTO;
import com.zmn.oms.model.dto.order.proxy.CreateOrderDTO;
import com.zmn.oms.model.dto.order.proxy.OrderLogDTO;
import com.zmn.oms.model.dto.order.proxy.UpdateOrderDTO;
import com.zmn.oms.model.dto.product.OrderProductDTO;
import com.zmn.oms.model.dto.track.OrderTrackDTO;
import com.zmn.oms.model.dto.track.OrderTrackDetailDTO;
import com.zmn.oms.model.entity.order.OrderExtend;
import com.zmn.oms.model.entity.track.OrderTrackQuery;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.model.entity.work.OrderWorkLogChange;
import com.zmn.oms.model.vo.track.OrderTrackVO;
import com.zmn.oms.model.vo.work.ZsOrderWorkVO;
import com.zmn.oms.services.interfaces.order.OrderExtendService;
import com.zmn.oms.services.interfaces.serviceitem.OrderServiceItemService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.oms.third.shunfeng.ShunfengConsts;
import com.zmn.oms.third.shunfeng.ShunfengUtil;
import com.zmn.oms.third.shunfeng.api.*;
import com.zmn.oms.third.shunfeng.dto.CPReuqestDTO;
import com.zmn.oms.third.shunfeng.dto.SFRequestDTO;
import com.zmn.oms.third.shunfeng.dto.SFResponseDTO;
import com.zmn.oms.third.shunfeng.service.ShunfengService;
import com.zmn.oms.zmn.business.interfaces.proxy.ProxyOrderBService;
import com.zmn.oms.zmn.business.interfaces.work.ZsOrderWorkQueryBService;
import com.zmn.oms.zmn.business.interfaces.work.autoflow.WorkFlowContextBService;
//import com.zmn.plat.common.dto.orderconfig.documentarycontent.DocumentaryContentDIO;
//import com.zmn.plat.common.dto.orderconfig.documentarycontent.DocumentaryContentDRO;
//import com.zmn.plat.dubbo.interfaces.orderconfig.documentarycontent.DocumentaryContentListRemoteService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 顺丰安装渠道对接的接口实现类
 *
 * @author xiewenbing
 * @date  2020/12//09 17:00
 */
@Slf4j
@Service
public class ShunfengServiceImpl implements ShunfengService {
    
    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
    protected AreaListRemoteService areaListRemoteService;

    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
    protected ChannelProductThirdListRemoteService channelProductThirdListRemoteService;

/*    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
    protected DocumentaryContentListRemoteService documentaryContentListRemoteService;*/

    @Autowired
    protected OrderWorkService orderWorkService;

    @Autowired
    protected OrderExtendService orderExtendService;

    @Autowired
    protected ZsOrderWorkQueryBService zsOrderWorkQueryBService;

    @Autowired
    protected WorkFlowContextBService workFlowContextBService;

    @Autowired
    protected ProxyOrderBService proxyOrderBService;

    @Autowired
    protected OrderTrackBService orderTrackBService;

    @Autowired
    protected OrderServiceItemService orderServiceItemService;

    @Autowired
    protected RedisManager redisManager;

    @Autowired
    protected BaiduMapBService baiduMapBService;

    /**
     * 处理订单任务请求
     *
     * @param requestDTO
     * @throws OmsBaseException
     */
    @Override
    public void handleOrderTaskRequest(SFRequestDTO requestDTO) throws OmsBaseException {

        log.info("【{}】收到订单任务通知【{}】", ShunfengConsts.CHANNEL_NAME,requestDTO.getMsgData());

        // 解析数据
        SFOrderTaskData orderTaskData;
        try {
            JSONObject jsonObject = JSON.parseObject(requestDTO.getMsgData());
            if (Objects.isNull(jsonObject)) {
                throw new OmsBaseException("解析接口JSON数据失败");
            }

            String orderListData = jsonObject.getString("orderList");
            if (StringUtils.isBlank(orderListData)) {
                throw new OmsBaseException("读取订单数据失败");
            }

            List<SFOrderTaskData> orderTaskDataList = JSON.parseArray(orderListData, SFOrderTaskData.class);
            if (CollectionUtils.isEmpty(orderTaskDataList)) {
                throw new OmsBaseException("订单数据列表解析失败");
            }

            orderTaskData = orderTaskDataList.get(0);
        } catch (Exception exception) {
            throw new OmsBaseException("解析接口数据异常");
        }

        if (Objects.isNull(orderTaskData)) {
            throw new OmsBaseException("订单数据错误");
        }

        // 判断订单状态
        switch (orderTaskData.getSupplierOrderStatus()) {
            case ShunfengConsts.ORDER_STATUS_UPDATE:
                // 新单/更新
                this.updateOrder(orderTaskData);
                break;
            case ShunfengConsts.ORDER_STATUS_CANCEL:
                // 取消
                this.cancelOrder(orderTaskData);
                break;
            default:
                throw new OmsBaseException("未知的订单状态");
        }
    }

    /**
     * 处理到货请求
     *
     * @param requestDTO
     * @throws OmsBaseException
     */
    @Override
    public void handleArrivalNoticeRequest(SFRequestDTO requestDTO) throws OmsBaseException {

        log.info("【{}】收到到货信息通知【{}】", ShunfengConsts.CHANNEL_NAME,requestDTO.getMsgData());

        // 解析数据
        SFArrivalNoticeData noticeData;
        try {
            noticeData = JSON.parseObject(requestDTO.getMsgData(),SFArrivalNoticeData.class);
        } catch (Exception exception) {
            throw new OmsBaseException("解析接口数据异常");
        }

        if (Objects.isNull(noticeData)) {
            throw new OmsBaseException("解析接口数据失败");
        }

        ZsOrderWorkVO zsOrderWorkVO = zsOrderWorkQueryBService.findOrderWorkByOuterId(noticeData.getWaybillNo(),OrderConsts.CHANNEL_ID_SF_INSTALL);
        if (Objects.isNull(zsOrderWorkVO)) {
            throw new OmsBaseException("查找不到对应的订单");
        }

        if (zsOrderWorkVO.getStatus() <= OrderStatusConsts.ORDER_STATUS_CONFIRM) {
            // 工单自动流转
            workFlowContextBService.asyncAutoFlow(zsOrderWorkVO.getOrderId(), zsOrderWorkVO.getWorkId());
        }

        // 发起跟单
        this.autoOrderTrack(zsOrderWorkVO);
    }

    /**
     * 同步订单预约时间
     * @param orderWorkLogChange
     * @throws OmsBaseException
     */
    @Override
    public void syncOrderDutytime(OrderWorkLogChange orderWorkLogChange) throws OmsBaseException {

        // 参数验证
        if (Objects.isNull(orderWorkLogChange)) {
            throw new OmsBaseException("参数为空");
        }

        // 回传操作码
        int operateCode;

        // 预约时间判断
        Date dutyTime = orderWorkLogChange.getDutyTime();
        if (Objects.isNull(dutyTime)) {

            // 预约没有修改
            if (!Objects.equals(OrderDutyConsts.DUTY_STATUS_FAIL, orderWorkLogChange.getDutyStatus())) {
                return;
            }

            // 预约失败
            operateCode = ShunfengConsts.NOTIFY_CODE_DUTY_FAILED;
        } else {

            // 预约成功
            operateCode = ShunfengConsts.NOTIFY_CODE_DUTY_SUCCESS;
        }

        // 生成回传数据
        SFOrderOperateData orderOperateData = buildOrderOperateData(orderWorkLogChange,operateCode);
        if (Objects.isNull(orderOperateData)) {
            throw new OmsBaseException("生成回传数据失败");
        }

        if (operateCode == ShunfengConsts.NOTIFY_CODE_DUTY_SUCCESS) {
            orderOperateData.setAppTime(DateUtil.toString(dutyTime));
        }

        // 发送回传数据
        String syncResponse = this.sendOrderOperateData(orderOperateData);

        log.info("【{}】同步预约时间，返回：【{}】",ShunfengConsts.CHANNEL_NAME,syncResponse);

        // 解析返回数据
        this.parseSyncResponse(syncResponse);
    }

    /**
     * 同步订单派单
     * @param orderWorkLogChange
     * @throws OmsBaseException
     */
    @Override
    public void syncOrderDistribute(OrderWorkLogChange orderWorkLogChange) throws OmsBaseException {

        // 参数验证
        if (Objects.isNull(orderWorkLogChange)) {
            throw new OmsBaseException("参数为空");
        }

        // 生成回传数据
        SFOrderOperateData orderOperateData = buildOrderOperateData(orderWorkLogChange,ShunfengConsts.NOTIFY_CODE_DISTRIBUTE);
        if (Objects.isNull(orderOperateData)) {
            throw new OmsBaseException("生成回传数据失败");
        }

        // 发送回传数据
        String syncResponse = this.sendOrderOperateData(orderOperateData);

        log.info("【{}】同步派单，返回：【{}】",ShunfengConsts.CHANNEL_NAME,syncResponse);

        // 解析返回数据
        this.parseSyncResponse(syncResponse);
    }

    /**
     * 同步订单完成
     * @param orderWorkLogChange
     * @throws OmsBaseException
     */
    @Override
    public void syncOrderComplete(OrderWorkLogChange orderWorkLogChange) throws OmsBaseException {

        // 参数验证
        if (Objects.isNull(orderWorkLogChange)) {
            throw new OmsBaseException("参数为空");
        }

        // 生成回传数据
        SFOrderOperateData orderOperateData = buildOrderOperateData(orderWorkLogChange,ShunfengConsts.NOTIFY_CODE_COMPLETE);
        if (Objects.isNull(orderOperateData)) {
            throw new OmsBaseException("生成回传数据失败");
        }

        // 发送回传数据
        String syncResponse = this.sendOrderOperateData(orderOperateData);

        log.info("【{}】同步订单完成，返回：【{}】",ShunfengConsts.CHANNEL_NAME,syncResponse);

        // 解析返回数据
        this.parseSyncResponse(syncResponse);
    }

    /**
     * 同步订单失败
     *
     * @param orderId
     * @param failedReason
     * @throws OmsBaseException
     */
    @Override
    public void syncOrderFailed(Long orderId, String failedReason, String imageUrl) throws OmsBaseException {

        // 查询信息
        OrderExtend orderExtend = orderExtendService.findOrderExtendByOrderId(orderId);
        if (Objects.isNull(orderExtend)) {
            throw new OmsBaseException("查询不到对应的订单信息");
        }

        this.addMasterOperateLog(orderId,"订单安装异常图片回传成功");

        OrderWorkLogChange orderWorkLogChange = new OrderWorkLogChange();
        // 参数验证
        if (Objects.isNull(orderWorkLogChange)) {
            throw new OmsBaseException("生成回传参数失败");
        }

        orderWorkLogChange.setOrderId(orderId);
        orderWorkLogChange.setWorkId(orderId);

        // 生成回传数据
        SFOrderOperateData orderOperateData = buildOrderOperateData(orderWorkLogChange,ShunfengConsts.NOTIFY_CODE_INSTALL_FAILED);
        if (Objects.isNull(orderOperateData)) {
            throw new OmsBaseException("生成回传数据失败");
        }

        orderOperateData.setContent(String.format("安装异常，取消原因：%s",failedReason));

        try {
            // 发送回传数据
            String syncResponse = this.sendOrderOperateData(orderOperateData);

            log.info("【{}】同步订单异常完成，返回：【{}】",ShunfengConsts.CHANNEL_NAME,syncResponse);

            // 解析返回数据
            this.parseSyncResponse(syncResponse);
            this.addLog(orderId,orderOperateData.getWaybillNo(),"同步订单异常成功");

        } catch (OmsBaseException omsBaseException) {

            this.addLog(orderId,orderOperateData.getWaybillNo(),"同步订单异失败");
            throw omsBaseException;
        }

        // 保存信息
        try {
            SFOrderOuterDataDTO orderOuterDataDTO = JSON.parseObject(orderExtend.getOuterData(), SFOrderOuterDataDTO.class);
            orderOuterDataDTO.setFailedReason(failedReason);
            orderOuterDataDTO.setFailedImageUrl(imageUrl);

            orderExtend.setOuterData(JSON.toJSONString(orderOuterDataDTO));

        } catch (Exception exception) {
            throw new OmsBaseException("解析同步数据异常");
        }

        orderExtendService.updateOrderExtend(orderExtend);
    }

    /**
     * 保存订单完成的图片
     *
     * @param orderId
     * @param imageUrl
     * @throws OmsBaseException
     */
    @Override
    public void saveOrderCompleteImage(Long orderId, String imageUrl) throws OmsBaseException {

        // 查询信息
        OrderExtend orderExtend = orderExtendService.findOrderExtendByOrderId(orderId);
        if (Objects.isNull(orderExtend)) {
            throw new OmsBaseException("查询不到对应的订单信息");
        }

        this.addMasterOperateLog(orderId,"订单完成图片回传成功");

        // 保存信息
        try {
            SFOrderOuterDataDTO orderOuterDataDTO = JSON.parseObject(orderExtend.getOuterData(), SFOrderOuterDataDTO.class);
            orderOuterDataDTO.setCompleteImageUrl(imageUrl);

            orderExtend.setOuterData(JSON.toJSONString(orderOuterDataDTO));

        } catch (Exception exception) {
            throw new OmsBaseException("解析同步数据异常");
        }

        orderExtendService.updateOrderExtend(orderExtend);
    }

    /**
     * 读取订单扩展信息
     *
     * @param orderId
     * @return
     * @throws OmsBaseException
     */
    @Override
    public SFOrderOuterDataDTO getOrderOutData(Long orderId) throws OmsBaseException {

        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId,orderId);
        if (Objects.isNull(orderWork)) {
            throw new OmsBaseException("查询不到对应的订单信息");
        }

        if (StringUtils.isBlank(orderWork.getOuterId()) || !orderWork.getInputType().equals(OrderConsts.ORDER_INPUT_TYPE_API)) {
            throw new OmsBaseException("订单无需回传图片资料");
        }

        // 查询信息
        OrderExtend orderExtend = orderExtendService.findOrderExtendByOrderId(orderId);
        if (Objects.isNull(orderExtend)) {
            throw new OmsBaseException("查询不到对应的订单数据");
        }

        // 查询信息
        SFOrderOuterDataDTO orderOuterDataDTO;
        try {
            orderOuterDataDTO = JSON.parseObject(orderExtend.getOuterData(), SFOrderOuterDataDTO.class);

        } catch (Exception exception) {
            throw new OmsBaseException("读取和解析数据失败");
        }

        return orderOuterDataDTO;
    }

    /**
     * 验证是否可以订单完成
     *
     * @param orderId
     * @param workId
     * @throws OmsBaseException
     */
    @Override
    public void verifyCompleteOrder(Long orderId,Long workId) throws OmsBaseException {

        // 判断功能是否开启
        if (!ShunfengConsts.POWER_ON) {
            log.info("【{}】暂不支持，不需要订单完成验证", ShunfengConsts.CHANNEL_NAME);
            return;
        }

        // 参数判断
        if (NumberUtil.isNullOrZero(orderId) || NumberUtil.isNullOrZero(workId)) {
            throw new OmsBaseException("参数不能为空");
        }

        // 查找工单
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId,workId);
        if (Objects.isNull(orderWork)) {
            throw new OmsBaseException("查找不到对应的工单");
        }

        if (!Objects.equals(orderWork.getInputType(),OrderConsts.ORDER_INPUT_TYPE_API)) {
            log.info("【{}】的录入方式不为API接入，不需要订单完成验证", ShunfengConsts.CHANNEL_NAME);
            return;
        }

        if (CollectionUtils.isEmpty(orderServiceItemService.listByOrderId(orderId))) {
            throw new OmsBaseException("订单没有选择服务项");
        }

        OrderExtend orderExtend = orderExtendService.findOrderExtendByOrderId(orderId);
        if (Objects.isNull(orderExtend)) {
            throw new OmsBaseException("查询不到对应的订单数据");
        }

        // 查询信息
        SFOrderOuterDataDTO orderOuterDataDTO;
        try {
            orderOuterDataDTO = JSON.parseObject(orderExtend.getOuterData(), SFOrderOuterDataDTO.class);

        } catch (Exception exception) {
            throw new OmsBaseException("解析订单图片回传数据失败");
        }

        if (Objects.isNull(orderOuterDataDTO)) {
            throw new OmsBaseException("读取订单图片回传数据失败，请重试");
        }

        if (StringUtil.isBlank(orderOuterDataDTO.getFailedImageUrl()) && StringUtil.isBlank(orderOuterDataDTO.getCompleteImageUrl())) {
            throw new OmsBaseException("请先回传订单图片");
        }
    }

    /**
     * 创建或更新订单
     *
     * @param orderTaskData
     * @throws OmsBaseException
     */
    protected void updateOrder(SFOrderTaskData orderTaskData) throws OmsBaseException {

        if (Objects.equals(orderTaskData.getServiceType(),ShunfengConsts.SERVICE_TYPE_PICKUP_AND_INSTALL)) {

            log.info("【{}】提货+安装的服务暂不处理",ShunfengConsts.CHANNEL_NAME);
            throw new OmsBaseException("提货+安装的服务暂不支持");
        }

        // redis查找是否创道订单
        String redisKey = String.format(RedisKeyConsts.SF_PULL_ORDER_REDIS_KEY,orderTaskData.getWaybillNo());
        String redisValue = redisManager.get(redisKey);
        if (StringUtils.isNotBlank(redisValue) && redisValue.compareToIgnoreCase(orderTaskData.getTaskCode())==0) {
            log.info("【{}】有对应的订单正在处理中,【{}】【{}】",ShunfengConsts.CHANNEL_NAME, orderTaskData.getWaybillNo(),orderTaskData.getTaskCode());
            throw new OmsBaseException("有相同的订单正在处理中");
        }

        // 通过外部订单id和渠道查找订单
        ZsOrderWorkVO zsOrderWorkVO = zsOrderWorkQueryBService.findOrderWorkByOuterId(orderTaskData.getWaybillNo(),OrderConsts.CHANNEL_ID_SF_INSTALL);
        if (Objects.nonNull(zsOrderWorkVO) || StringUtils.isNotBlank(redisValue)) {

            String userPhone = orderTaskData.getReceiverPhone();
            String userAddress = orderTaskData.getReceiverAddress();

            // 电话和地址信息判断
            if (StringUtils.isBlank(userPhone) && StringUtils.isBlank(userAddress)) {
                log.info("【{}】【{}】信息中电话和店址为空，无需更新",ShunfengConsts.CHANNEL_NAME,orderTaskData.toString());
                return;
            }

            // 电话和地址信息没有更改
            if (Objects.equals(zsOrderWorkVO.getUserAddress(),userAddress) &&
                    Objects.equals(zsOrderWorkVO.getUserPhone(),userPhone)) {
                log.info("【{}】【{}】信息中电话和店址未改变，无需更新",ShunfengConsts.CHANNEL_NAME,orderTaskData.toString());
                return;
            }

            Long orderId = Optional.ofNullable(zsOrderWorkVO.getOrderId()).orElse(Long.valueOf(redisValue));

            // 更新订单
            UpdateOrderDTO updateOrderDTO = new UpdateOrderDTO();
            updateOrderDTO.setOrderId(orderId);
            updateOrderDTO.setPhone(userPhone);
            updateOrderDTO.setAddress(userAddress);
            try {
                proxyOrderBService.updateOrder(updateOrderDTO);
            } catch (OmsBaseException exception) {
                log.info("【{}】更新订单异常，【{}】【{}】,异常【{}】",ShunfengConsts.CHANNEL_NAME, userPhone, userAddress, exception.getMessage());
                throw new OmsBaseException("订单信息更新失败");
            }

            // 增加日志
            String logRemark =String.format("订单信息更新，用户地址 ：%s -> %s ,用户电话：%s -> %s",
                    zsOrderWorkVO.getUserAddress(),userAddress,zsOrderWorkVO.getUserPhone(),userPhone);
            this.addLog(zsOrderWorkVO.getOrderId(),zsOrderWorkVO.getOuterId(),logRemark);

            return;
        }

        log.info("【{}】创建订单【{}】", ShunfengConsts.CHANNEL_NAME,orderTaskData.toString());

        // 保存redis
        redisManager.setex(redisKey,orderTaskData.getTaskCode(),600);

        OrderBO orderBO;

        try {
            // 生成创建订单数据
            CreateOrderDTO createOrderDTO = buildCreateOrderDTO(orderTaskData);

            // 新建订单
            orderBO = proxyOrderBService.createOrder(createOrderDTO);
        } catch (OmsBaseException exception) {
            log.info("【{}】创建订单异常，OmsBaseException【{}】",ShunfengConsts.CHANNEL_NAME, exception.getMessage());

            // 删除redis
            redisManager.del(redisKey);

            throw new OmsBaseException("创建订单失败");
        } catch (Exception exception) {

            log.info("【{}】 创建订单失异常 Exception【{}】",ShunfengConsts.CHANNEL_NAME,exception.getMessage());

            // 删除redis
            redisManager.del(redisKey);

            throw new OmsBaseException("创建订单失败");
        }

        // 保存redis
        redisManager.setex(redisKey,String.valueOf(orderBO.getOrder().getOrderId()),600);

        log.info("【{}】创建订单成功【{}】", ShunfengConsts.CHANNEL_NAME,orderBO.getOrder().getOrderId());
    }

    /**
     * 生成创建订单的数据
     *
     * @param orderTaskData
     * @return
     * @throws OmsBaseException
     */
    protected CreateOrderDTO buildCreateOrderDTO(SFOrderTaskData orderTaskData) throws OmsBaseException {

        // 参数检验
        if (StringUtils.isBlank(orderTaskData.getTaskCode())) {
            throw new OmsBaseException("订单任务编码为空");
        }

        if (StringUtils.isBlank(orderTaskData.getWaybillNo())) {
            throw new OmsBaseException("订单母单号为空");
        }

        if (StringUtils.isBlank(orderTaskData.getReceiverPhone())) {
            throw new OmsBaseException("联系人电话为空");
        }

        if (StringUtils.isBlank(orderTaskData.getReceiverAddress())) {
            throw new OmsBaseException("联系人地址为空");
        }

        if (CollectionUtils.isEmpty(orderTaskData.getInstallTypes())) {
            throw new OmsBaseException("订单品类为空");
        }

        // 订单创建数据
        CreateOrderDTO createOrderDTO = new CreateOrderDTO();

        // 输入类型
        createOrderDTO.setInputType(OrderConsts.ORDER_INPUT_TYPE_API);

        // 渠道id
        createOrderDTO.setChannelId(OrderConsts.CHANNEL_ID_SF_INSTALL);

        // 外部订单id - 母单号
        createOrderDTO.setOuterId(orderTaskData.getWaybillNo());

        // 外部订单id - 任务编码
        createOrderDTO.setExtOuterId(orderTaskData.getTaskCode());

        // 联系人
        createOrderDTO.setContactName(orderTaskData.getReceiverName());

        // 联系人电话
        createOrderDTO.setTelephone(orderTaskData.getReceiverPhone());

        // 性别
        createOrderDTO.setGender(GlobalDict.GENDER_NO);

        // 预约时间
        createOrderDTO.setDutyTime(null);

        // 地址
        createOrderDTO.setAddress(orderTaskData.getReceiverAddress());

        // 厂商单
        createOrderDTO.setFactory(GlobalConsts.YES);

        // 备注
        createOrderDTO.setRemark(orderTaskData.getRemark());

        // 业务类型
        createOrderDTO.setBizType(GlobalConsts.BIZ_TYPE_F);

        // 平台
        createOrderDTO.setPlat(GlobalConsts.PLAT_MARK_YEYX);

        // 禁止弃单
        createOrderDTO.setDisableDiscard(GlobalConsts.YES);

        // 操作人
        createOrderDTO.setOperator("系统");

        // 操作人id
        createOrderDTO.setOperatorId((long) GlobalConsts.OPERATE_USER_TYPE_SYSTEM);

        // 操作者类型
        createOrderDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_CHANNEL);

        // 城市id
        Integer cityId = 500100;
        do {
            // 详细地址获取经纬度
            LngLatLocation areaLocation = baiduMapBService.location(orderTaskData.getReceiverAddress());
            if (Objects.isNull(areaLocation)) {
                log.info("【{}】地址信息无法解析",ShunfengConsts.CHANNEL_NAME);
                break;
            }

            createOrderDTO.setLatitude(Double.valueOf(areaLocation.getLat()));
            createOrderDTO.setLongitude(Double.valueOf(areaLocation.getLng()));

            // 经纬度查找区域信息
            ResponseDTO<com.zmn.base.common.data.common.dro.area.AreaDRO> areaResponse = areaListRemoteService.getAreaByLatAndLng(Double.valueOf(areaLocation.getLng()), Double.valueOf(areaLocation.getLat()));
            if (Objects.isNull(areaResponse) || Objects.isNull(areaResponse.getData())) {
                log.info("【{}】根据经纬度查找地址信息失败",ShunfengConsts.CHANNEL_NAME);
                break;
            }

            cityId = areaResponse.getData().getParentId();

            // 再设一次经纬度
            Double longitude = Double.valueOf(areaResponse.getData().getLongitude());
            Double latitude = Double.valueOf(areaResponse.getData().getLatitude());
            createOrderDTO.setLongitude(longitude);
            createOrderDTO.setLatitude(latitude);

        } while (false);

        createOrderDTO.setCityId(cityId);

        // 产品
        List<OrderProductDTO> orderProductList =  new LinkedList<>();
        OrderProductDTO orderProductDTO = new OrderProductDTO();

        String channelProductId = orderTaskData.getInstallTypes().get(0).getInstallTypeCode();

        // 查找产品id
        log.info("【{}】 #ChannelProductMapListRemoteService#listByChannelIdAndProductParentIdAndProductSubId# 入参【{}】【{}】",
                ShunfengConsts.CHANNEL_NAME, OrderConsts.CHANNEL_ID_SF_INSTALL, channelProductId);

        ResponseDTO<List<ProductBaseDRO>> servProductListResponseDTO = channelProductThirdListRemoteService.listByChannelIdAndProductParentIdAndSubId(OrderConsts.CHANNEL_ID_SF_INSTALL,
                channelProductId, null);
        log.info("【{}】 #ChannelProductMapListRemoteService#listByChannelIdAndProductParentIdAndProductSubId# 出参【{}】",
                ShunfengConsts.CHANNEL_NAME,servProductListResponseDTO.toString());

        if (!servProductListResponseDTO.isSuccess() || Objects.isNull(servProductListResponseDTO.getData()) ||
                servProductListResponseDTO.getData().isEmpty()) {
            orderProductDTO.setProductId(OrderConsts.CHANNEL_DISABLED_PRODUCT_ID);
        } else {
            orderProductDTO.setProductId(servProductListResponseDTO.getData().get(0).getProductId());
        }

        orderProductDTO.setNumber(orderTaskData.getInstallTypes().get(0).getCount());
        orderProductList.add(orderProductDTO);
        createOrderDTO.setOrderProductList(orderProductList);

        // 日志记录
        StringBuilder sbOperateLog = new StringBuilder();
        StringJoiner sjTypeName = new StringJoiner(",");
        StringJoiner sjTypeCode = new StringJoiner(",");
        orderTaskData.getInstallTypes().forEach(installType->{
            sjTypeCode.add(installType.getInstallTypeCode());
            sjTypeName.add(installType.getInstallTypeName());
        });

        sbOperateLog.append("<br/> 安装品类编码：").append(sjTypeCode.toString()).
                append("<br/> 安装品类名称：").append(sjTypeName.toString()).
                append("<br/> 收件人姓名：").append(orderTaskData.getReceiverName()).
                append("<br/> 收件人电话：").append(orderTaskData.getReceiverPhone()).
                append("<br/> 收件人地址：").append(orderTaskData.getReceiverAddress()).append("<br/> 订单状态：新增<br/>");

        createOrderDTO.setOperatorLogRemark(sbOperateLog.toString());

        // 扩展数据
        SFOrderOuterDataDTO orderOuterDataDTO = BeanMapper.map(orderTaskData,SFOrderOuterDataDTO.class);
        if (Objects.nonNull(orderOuterDataDTO)) {
            createOrderDTO.setOuterData(JSON.toJSONString(orderOuterDataDTO));
        }

        return createOrderDTO;
    }

    /**
     * 取消订单
     *
     * @param orderTaskData
     * @throws OmsBaseException
     */
    protected void cancelOrder(SFOrderTaskData orderTaskData) throws OmsBaseException {

        log.info("【{}】取消订单，【{}】",ShunfengConsts.CHANNEL_NAME,orderTaskData.getWaybillNo());

        ZsOrderWorkVO zsOrderWorkVO = zsOrderWorkQueryBService.findOrderWorkByOuterId(orderTaskData.getWaybillNo(),OrderConsts.CHANNEL_ID_SF_INSTALL);
        if (Objects.isNull(zsOrderWorkVO)) {
            throw new OmsBaseException("查找不到对应的订单");
        }

        // 取消订单数据构建
        CancelOrderDTO cancelDTO = new CancelOrderDTO();
        cancelDTO.setOrderId(zsOrderWorkVO.getOrderId());
        cancelDTO.setOuterId(zsOrderWorkVO.getOuterId());
        cancelDTO.setChannelId(OrderConsts.CHANNEL_ID_SF_INSTALL);
        cancelDTO.setOperatorId(Long.valueOf(OrderConsts.CHANNEL_ID_SF_INSTALL));
        cancelDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_CHANNEL);
        cancelDTO.setRemark("渠道方取消");

        // 取消订单
        try {
            proxyOrderBService.cancelOrder(cancelDTO);
        } catch (OmsBaseException omsBaseException) {

            log.error("【{}】取消订单失败 消息:[{}]",ShunfengConsts.CHANNEL_NAME, omsBaseException.getMessage());
            throw new OmsBaseException(Optional.ofNullable(omsBaseException.getMessage()).orElse(""));
        }
    }

    /**
     * 增加操作日志
     *
     * @param orderId
     * @param outerId
     * @param logRemark
     */
    protected void addLog(Long orderId, String outerId, String logRemark) throws OmsBaseException {

        // 构造参数
        OrderLogDTO orderLogDTO = new OrderLogDTO();
        orderLogDTO.setOrderId(orderId);
        orderLogDTO.setOuterId(outerId);
        orderLogDTO.setChannelId(OrderConsts.CHANNEL_ID_SF_INSTALL);
        orderLogDTO.setOperatorId((long)OrderConsts.CHANNEL_ID_SF_INSTALL);
        orderLogDTO.setOperatorType(com.zmn.common.constant.GlobalConsts.OPERATE_USER_TYPE_CHANNEL);
        orderLogDTO.setType(OrderLogConsts.ORDER_LOG_TYPE_CHANNEL_REMARK);
        orderLogDTO.setOperatorLogRemark(logRemark);

        proxyOrderBService.addOrderLog(orderLogDTO);
    }

    /**
     * 增加H5页面师傅回传订单完成图片或异常图片的操作日志
     *
     * @param orderId
     * @param logRemark
     */
    protected void addMasterOperateLog(Long orderId,String logRemark) throws OmsBaseException {

        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId,orderId);
        if (Objects.isNull(orderWork)) {
            return;
        }

        // 构造参数
        OrderLogDTO orderLogDTO = new OrderLogDTO();
        orderLogDTO.setOrderId(orderId);
        orderLogDTO.setOuterId(orderWork.getOuterId());
        orderLogDTO.setChannelId(OrderConsts.CHANNEL_ID_SF_INSTALL);
        orderLogDTO.setOperatorId((long)orderWork.getMasterId());
        orderLogDTO.setOperatorType(com.zmn.common.constant.GlobalConsts.OPERATE_USER_TYPE_MASTER);
        orderLogDTO.setType(OrderLogConsts.ORDER_LOG_TYPE_PLAT_MASTER_REMARK);
        orderLogDTO.setOperatorLogRemark(logRemark);

        proxyOrderBService.addOrderLog(orderLogDTO);
    }

     /**
     * 生成订单状态回传基本数据
     *
     * @param orderWorkLogChange
     * @return
     */
    protected SFOrderOperateData buildOrderOperateData(OrderWorkLogChange orderWorkLogChange,int operateCode) {

        Long orderId = orderWorkLogChange.getOrderId();
        Long workId = orderWorkLogChange.getWorkId();

        // 查找工单信息
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId,workId);
        if (Objects.isNull(orderWork)) {
            log.info("【{}】订单状态回传基本数据失败 - 查找不到工单信息", ShunfengConsts.CHANNEL_NAME);
            return null;
        }

        // 查找扩展信息
        OrderExtend orderExtend = orderExtendService.findMiniOrderExtendByOrderId(orderId);
        if (Objects.isNull(orderExtend)) {
            log.info("【{}】订单状态回传基本数据失败 - 查找不到工单的扩展信息", ShunfengConsts.CHANNEL_NAME);
            return null;
        }

        // 生成回传数据
        SFOrderOperateData orderOperateData = new SFOrderOperateData();
        if (Objects.isNull(orderOperateData)) {
            return null;
        }

        // 母单号 - 外部订单号
        orderOperateData.setWaybillNo(orderWork.getOuterId());

        // 任务编码 - 外部扩展订单号
        orderOperateData.setTaskCode(orderExtend.getExtOuterId());

        // 操作码
        orderOperateData.setOperateCode(operateCode);

        // 操作描述
        orderOperateData.setContent(ShunfengConsts.getOperateteContentByCode(operateCode));

        // 操作时间
        orderOperateData.setOperateTime(DateUtil.toString(Optional.ofNullable(orderWorkLogChange.getOpTime()).orElse(DateUtil.getNow())));

        // 唯一校验码
        orderOperateData.setUniqueId(UUID.randomUUID().toString());

        // 预约时间
        orderOperateData.setAppTime(DateUtil.toString(orderWork.getDutyTime()));

        // 安装师傅联系方式
        orderOperateData.setInstallContact(
                (operateCode == ShunfengConsts.NOTIFY_CODE_DISTRIBUTE)
                        ? ShunfengConsts.MASTER_PHONE
                        : ShunfengConsts.OPERATOR_PHONE
        );

        // 安装师傅
        orderOperateData.setInstallMaster(
                (operateCode == ShunfengConsts.NOTIFY_CODE_DISTRIBUTE
                        || operateCode == ShunfengConsts.NOTIFY_CODE_INSTALL_FAILED)
                        ? Optional.ofNullable(orderWork.getMasterName())
                                    .filter(name -> name.length() >= 1)
                                    .map(name -> String.format("%s工程师", name.substring(0,1)))
                                    .orElse("工程师")
                        : orderWorkLogChange.getOperatorName()
        );

        // 当前城市
        ResponseDTO<AreaDRO> areaResponseDTO = areaListRemoteService.getById(orderWork.getCityId());
        if (areaResponseDTO.isSuccess() && Objects.nonNull(areaResponseDTO.getData())) {
            orderOperateData.setCity(areaResponseDTO.getData().getCityName());
        }

        log.info("【{}】生成订单状态回传基本数据【{}】", ShunfengConsts.CHANNEL_NAME, JSON.toJSONString(orderOperateData));
        return orderOperateData;
    }

    /**
     * 发送回传数据
     *
     * @param orderOperateData
     * @throws OmsBaseException
     * @return String
     */
    protected String sendOrderOperateData(SFOrderOperateData orderOperateData) throws OmsBaseException {

        // 生成同步数据
        CPReuqestDTO cpReuqestDTO = new CPReuqestDTO();
        if (Objects.isNull(cpReuqestDTO)) {
            throw new OmsBaseException("生成同步请求数据失败");
        }

        // 设置数据
        cpReuqestDTO.setPartnerID(ShunfengConsts.PARTNER_ID);
        cpReuqestDTO.setRequestID(UUID.randomUUID().toString());
        cpReuqestDTO.setServiceCode(ShunfengConsts.SERVICE_CODE_OPEARTION_UPLOAD);
        cpReuqestDTO.setTimestamp(DateUtil.getNowTimestampMillis());
        cpReuqestDTO.setMsgData(JSON.toJSONString(orderOperateData));
        cpReuqestDTO.setNonce(DateUtil.getNowTimestamp().intValue());
        ShunfengUtil.makeSign(cpReuqestDTO);

        // 转换成map
        Map<String,String> params = getRequestParam(cpReuqestDTO);

        // 发送请求
        String response = ShunfengUtil.postHttpRequest(ShunfengConsts.API_URL,params);
        if (StringUtils.isBlank(response)) {
            throw new OmsBaseException("发送回传请求失败");
        }

        return response;
    }

    /**
     * 将请求数据转换成map
     *
     * @param cpReuqestDTO
     * @return
     */
    protected Map<String,String> getRequestParam(CPReuqestDTO cpReuqestDTO) {

        Map<String,String> params = Maps.newHashMap();
        if (Objects.isNull(cpReuqestDTO)) {
            return params;
        }

        Class<?> requestClass = cpReuqestDTO.getClass();

        // 循环获取类和父类的字段，并取值
        while (requestClass!=null && !"java.lang.object".equals(requestClass.getName().toLowerCase())) {

            Field[] fields = requestClass.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                String name = field.getName();
                Object value = null;
                try {
                    value = field.get(cpReuqestDTO);
                } catch (IllegalAccessException exception) {
                    log.info("#ShunfengServiceImpl#getRequestParam# catch IllegalAccessException");
                }

                if (Objects.nonNull(value)) {
                    params.put(name, value.toString());
                }
            }

            requestClass = requestClass.getSuperclass();
        }

        return params;
    }

    /**
     * 解析同步返回的数据
     *
     * @param response
     * @throws OmsBaseException
     */
    protected void parseSyncResponse(String response) throws OmsBaseException {

        if (StringUtils.isBlank(response)) {
            return;
        }

        SFResponseDTO responseDTO;
        try {
            responseDTO = JSON.parseObject(response, SFResponseDTO.class);
        } catch (Exception e) {
            throw new OmsBaseException("解析返回数据异常");
        }

        if (Objects.isNull(responseDTO)) {
            throw new OmsBaseException("解析返回数据失败");
        }

        String resultCode = responseDTO.getApiResultCode();
        if (!Objects.equals(resultCode,ShunfengConsts.RESULT_CODE_SUCCESS)) {

            String errMsg = String.format("调用回传接口失败，结果码：%s，消息：%s",resultCode,
                    Optional.ofNullable(responseDTO.getApiErrorMsg()).orElse(ShunfengConsts.getResultCodeMsg(resultCode)));
            throw new OmsBaseException(errMsg);
        }

        if (StringUtils.isBlank(responseDTO.getApiResultData())) {
            throw new OmsBaseException("渠道处理数据为空");
        }

        SFResultData resultData;
        try {
            resultData = JSON.parseObject(responseDTO.getApiResultData(), SFResultData.class);
        } catch (Exception e) {
            throw new OmsBaseException("解析渠道处理结果数据异常");
        }

        if (Objects.isNull(resultData)) {
            throw new OmsBaseException("解析渠道处理结果数据失败");
        }

        if (resultData.getSuccess()) {
            return;
        }

        String resultErrMsg = String.format("渠道处理回传失败，结果码：%s，消息：%s",resultData.getErrorCode(),
                Optional.ofNullable(resultData.getErrorMessage()).orElse(""));

        throw new OmsBaseException(resultErrMsg);
    }

    /**
     * 用户已签收发起自动跟单
     *
     * @param zsOrderWorkVO
     */
    private void autoOrderTrack(ZsOrderWorkVO zsOrderWorkVO) {

        //查询是否存在用户签收跟单 && 跟单未完成
        OrderTrackQuery query = new OrderTrackQuery();
        query.setOrderId(zsOrderWorkVO.getOrderId());
        query.setWorkId(zsOrderWorkVO.getWorkId());
        query.setMapId(OrderConsts.ORDER_TRACT_SF_NOTICE_ID);
        query.setComplete(GlobalConsts.NO);
        Integer orderTrackCount = orderTrackBService.countByQuery(query);
        log.info("#ShunfengServiceImpl#orderTrackCount 查询跟单是否完成：【{}】", JSON.toJSONString(orderTrackCount));
        // 有进行中的跟单则不创建跟单
        if (orderTrackCount != null && orderTrackCount > 0) {
            return;
        }

        //查询指定的跟单信息
        /*List<OrderTrackVO> trackTypeList = Lists.newArrayList();
        DocumentaryContentDIO documentaryContentDIO = new DocumentaryContentDIO();
        documentaryContentDIO.setBizType(zsOrderWorkVO.getBizType());
        documentaryContentDIO.setStatus(com.zmn.common.constant.GlobalConsts.YES);
        documentaryContentDIO.setId(OrderConsts.ORDER_TRACT_SF_NOTICE_ID);
        log.info("#ShunfengServiceImpl#track 查询跟单项目入参：【{}】", JSON.toJSONString(documentaryContentDIO));
        ResponseDTO<List<DocumentaryContentDRO>> responseDTO = documentaryContentListRemoteService.listByQuery(documentaryContentDIO);
        log.info("#ShunfengServiceImpl#track 查询跟单项目出参：【{}】", JSON.toJSONString(responseDTO));

        if (!responseDTO.isSuccess() || CollectionUtils.isEmpty(responseDTO.getData())) {
            log.info("#ShunfengServiceImpl#trackTypeList 查询跟单项失败或为空，不处理--------");
            return;
        }

        responseDTO.getData().forEach(e -> {
            // 默认跟单等级为一级
            OrderTrackVO orderTrackVO = OrderTrackVO.builder().mapId(e.getId()).mapName(e.getContent()).level(OrderConsts.ORDER_TRACT_OTHER_TYPE_LEVEL).build();
            trackTypeList.add(orderTrackVO);
        });

        // 保存跟单信息
        OrderTrackDTO orderTrackDTO = new OrderTrackDTO();
        orderTrackDTO.setComplete(com.zmn.common.constant.GlobalConsts.NO);
        orderTrackDTO.setOrderId(zsOrderWorkVO.getOrderId());
        orderTrackDTO.setWorkId(zsOrderWorkVO.getWorkId());
        orderTrackDTO.setOperator("系统");
        orderTrackDTO.setOperatorId((long) zsOrderWorkVO.getChannelId());
        orderTrackDTO.setOperatorType(com.zmn.common.constant.GlobalConsts.OPERATE_USER_TYPE_CHANNEL);

        List<OrderTrackDetailDTO> detailDTOList = new ArrayList<>(trackTypeList.size());
        orderTrackDTO.setDetailDTOList(detailDTOList);

        trackTypeList.forEach(workTrackDTO -> {

            // 添加到跟单列表
            OrderTrackDetailDTO orderTrackDetailDTO = new OrderTrackDetailDTO();
            orderTrackDetailDTO.setMapId(workTrackDTO.getMapId());
            orderTrackDetailDTO.setMapName(workTrackDTO.getMapName());
            orderTrackDetailDTO.setRemark(workTrackDTO.getRemark());
            orderTrackDetailDTO.setLevel(workTrackDTO.getLevel());
            detailDTOList.add(orderTrackDetailDTO);
        });

        // 保存
        orderTrackBService.updateTrack(orderTrackDTO);*/
    }

    public static void main(String[] args) {

        String msgData = "{\"waybillNo\":\"202012161655\",\"taskCode\":\"SF1655\",\"subWaybillNos\":\"202012161655001\",\"receiverName\":\"X先生\",\"serviceType\":\"1\",\"receiverPhone\":\"13612341234\",\"receiverAddress\":\"北京市北土城元大都7号\",\"packageCount\":\"1\",\"version\":\"1.0\",\"supplierOrderStatus\":\"1\",\"remark\":\"测试\",\"installTypes\": [{\"installTypeCode\":\"SF-I01\",\"installTypeName\":\"电视安装\",\"count\":\"1\"}]}";
        SFOrderTaskData taskData = JSON.parseObject(msgData,SFOrderTaskData.class);

        System.out.println(taskData);
    }
}
